/**
 * @version 1.0
 * @author Ha Giang
 * @date
 */
package Communications;

import Configuration.Utils;
import java.io.*;
import java.net.*;
import java.util.*;

/**
 * Some Servers allow only one client at a time (for example: Printer). After a
 * connection closes, it automatically open a new connection for another client
 * to connect
 */
public class SingleUnicastServer implements Runnable {

    private ServerSocket serverSocket = null;
    private Socket clientSocket;
    private PrintWriter out = null;
    private BufferedReader in = null;
    int port;
    private Thread thread = null;
    private boolean stop = false;
    private List inputStream = new ArrayList();

    /**
     * Constructor
     *
     * @param port The port number
     */
    public SingleUnicastServer(int port) {
        this.port = port;
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            System.err.println("Could not listen on port:" + port);
        }
        clientSocket = null;
    }

    /**
     * Start the server
     */
    public void start() {
        if (thread == null) {
            thread = new Thread(this);
        }
        thread.start();

    }

    /**
     * Stop the server
     */
    public void stop() {
        if (thread != null) {
            thread.stop();
            thread = null;
        }
        stop = true;
    }

    @Override
    public void run() {
        while (thread != null && !stop) {

            System.out.println("Starting Single Unicast Server Listening on port "
                    + Utils.chnnl2Str(port) + "...");
            try {
                clientSocket = serverSocket.accept();
                out = new PrintWriter(clientSocket.getOutputStream(), true);
                in = new BufferedReader(
                        new InputStreamReader(clientSocket.getInputStream()));
                if (Utils.MODE == Utils.DEBUG_MODE) {
                    System.out.println("Single Unicast Server: You're connected on "
                            + Utils.chnnl2Str(port));
                }
            } catch (IOException e) {
                System.err.println("Could not listen on port:" + port);
                stop = true;
                e.printStackTrace();

            }

            //clear the stream
            inputStream.clear();

            for (;;) {
                try {
                    String s = in.readLine();
                    if (s != null) {
                        inputStream.add(s);
                        //System.out.println(s+ " added");
                    }
                    if (stop) {
                        break;
                    }
                } catch (Exception e) {
                    stop = true;
                }
            }
        }
    }

    /**
     * Get the IP address of the server
     *
     * @return a string contains IP address
     */
    public String getIp() {
        try {
            InetAddress addr = InetAddress.getLocalHost();
            // Get address
            String address = addr.getHostAddress();
            return address;
        } catch (UnknownHostException e) {
            return null;
        }
    }

    /**
     * Send a message to the connected client
     *
     * @param msg The message to send
     */
    public void sendMessage(String msg) {
        if (!clientSocket.isClosed()) {
            out.println(msg);
        }
    }

    /**
     * Get a message from the input stream
     *
     * @return
     */
    public String getMessage() {
        //wait until has a message
        while (inputStream.isEmpty() && !stop) {
        }

        if (!stop) {
            String s = inputStream.get(0).toString();
            inputStream.remove(0);
            return s;
        } else {
            stop();
            start();
            stop = false;
        }
        return null;
    }

    /**
     * Get the message stream
     *
     * @return A List contains the stream
     */
    public List getMessagesStream() {
        return inputStream;
    }

    /*
     * Close all connections
     */
    public void close() {
        try {
            serverSocket.close();
            clientSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] arg) {
        System.out.println("Server");
        SingleUnicastServer us = new SingleUnicastServer(Utils.UNICAST_NOTIFY_PORT);
        us.start();
        //ArrayList<String> inputStream = us.getMessagesStream();

        int count = 0;
        while (true) {
            String s = null;

            s = us.getMessage();
            if (s != null) {
                System.out.println("Server: " + s);
                //out.println(inputLine); 
                count++;
                //us.out.println(count);
                us.sendMessage(String.valueOf(count));

                if (s.equals("Bye.")) {
                    break;
                }
            }
        }
        us.close();
    }
}
